<?php
/**
 * @file WCParserNode.php
 *
 * @author Alejandro Dario Simi
 * @date $Date: 2013-04-30 02:04:27 +0000 (Tue, 30 Apr 2013) $
 *
 * $Id: WCParserNode.php 63 2013-04-30 02:04:27Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/tags/wcomix-1.0-BETA2/includes/parser/WCParserNode.php $
 */

require_once dirname(__FILE__)."/WCParserBehavior.php";

/**
 * @class WCParserNode
 * This class represent a portion of the text to be parsed. Basically it can
 * adopt two kind of behaviors:
 *	- Simple text:
 *		Given text is final and it needs no parsing.
 *	- Function execution
 *		Given text must be parsed by a function.
 */
class WCParserNode {
	protected $_id = false;
	protected $_function = false;
	protected $_params = false;
	/** @var WCParserBehavior */
	protected $_behavior = false;
	protected $_parentNode = false;
	protected $_children = array();
	/**
	 * @var WCParser
	 * This is the pointer to parser where this node is attached to.
	 */
	protected $_parser = false;

	//
	// Constructors.
	/**
	 * @param int $id Identificator for the new node.
	 * @param WCParser $parser Pointer to the parser this node must use.
	 */
	public function __construct($id, &$parser) {
		$this->_id = $id;
		$this->_parser = &$parser;
	}
	//
	// Public Methods.
	/**
	 * This method adds a sub-node.
	 *
	 * @param WCParserNode $child Node to add as child. It can either a
	 * string or a WCParserNode.
	 */
	public function addChild($child) {
		//
		// If the child is a WCParserNode, it's parrent is set to be
		// the current object.
		if($child instanceof self) {
			$child->parentNode($this);
		}
		$this->_children[] = $child;
	}
	/**
	 * Gets the list of sub-nodes.
	 *
	 * @return WCParserNode[] Returns the current list of sub-nodes.
	 */
	public function & children() {
		return $this->_children;
	}
	/**
	 * Gets the last error messege set by it's behavior.
	 *
	 * @return string Returns the last error message. If there is no behavior
	 * set, returns a message indication it.
	 */
	public function errorMessage() {
		return $this->_behavior ? $this->_behavior->errorMessage() : "No behavior assigned";
	}
	/**
	 * This methods sets which function must be performed on the current
	 * node. It depends on definitions made on $WCParserBehaviorMatrix.
	 *
	 * @param string $func Function name. If it is NULL, it will only
	 * return the current setting.
	 * @return string Return the currently set function name.
	 */
	public function func($func = null) {
		//
		// If $func is not null, it means it must be changed.
		if($func !== null) {
			global $WCParserBehaviorMatrix;
			//
			// Checking if there's a handler defined for the
			// specified function name.
			if(isset($WCParserBehaviorMatrix[$func])) {
				// Setting the current function name.
				$this->_function = $func;
				// Creating an object to manage the function.
				$this->_behavior = new $WCParserBehaviorMatrix[$this->_function]($this);
			} else {
				//
				// If the handler is not found it is shown as a
				// warning.
				trigger_error("Function '{$func}' handler is not set in \$WCParserBehaviorMatrix".($this->_function ? ". Function remain as '{$this->_function}'" : ""), E_USER_WARNING);
			}
		}

		return $this->_function;
	}
	/**
	 * Gets the id set for the current node.
	 *
	 * @return int Returns node id.
	 */
	public function id() {
		return $this->_id;
	}
	/**
	 * Node's status depends directly of it's assigned behavior, therefore,
	 * this method will call it to give an answer.
	 *
	 * @return boolean Returns true if it's behavior checks ok, or if it has
	 * no behavior assigned.
	 */
	public function isOk() {
		return $this->_behavior ? $this->_behavior->check() : true;
	}
	/**
	 * This method triggers the analysis of the node. This means execute the
	 * assign function or even trigger the same on each child.
	 *
	 * @return string Returns the resulting string of parsing the node. On
	 * error, it returns false.
	 */
	public function parse() {
		$out = false;
		//
		// Checking if there's no problem to run the parsing operation.
		if($this->isOk()) {
			//
			// If there is a behavior assigned, the result will
			// depend on it. Otherwise, result will depend on each
			// child.
			if($this->_behavior) {
				$out = $this->_behavior->get();
			} else {
				$out = $this->parseChildren();
			}
		} else {
			trigger_error("Node '{$this->id()}' is not Ok", E_USER_ERROR);
		}

		return $out;
	}
	/**
	 * This method walks over every node and triggers it to parse.
	 *
	 * @return string Returns the resulting string of parsing each node. On
	 * error returns false.
	 */
	public function parseChildren() {
		$out = false;

		//
		// Checking if the node can be parsed.
		if($this->isOk()) {
			$out = "";
			//
			// Analyzing each sub-node.
			foreach($this->_children as $nId => $node) {
				//
				// Checking if the sub-node is a WCParserNode.
				if($node instanceof WCParserNode) {
					//
					// Checking if the sub-node is ok to be
					// parsed.
					if($node->isOk()) {
						// Parsing the sub-node.
						$par = $node->parse();
						// Cheking if the sub-node
						// parsing result was an error.
						// In such case, the sub-nodes
						// process stops.
						if($par !== false) {
							$out .= $par;
						} else {
							$out = $par;
							break;
						}
					} else {
						/// @todo this should give more info.
						trigger_error("Node '{$nId}' is not Ok", E_USER_ERROR);
						$out = false;
						break;
					}
				} else {
					//
					// This means the node is just text,
					// in which case it is appended to the
					// result.
					$out .= $node;
				}
			}
		}

		return $out;
	}
	/**
	 * Gets the current parser assign for this node.
	 *
	 * @return WCParser Returns a pointer to this node's parser.
	 */
	public function & parser() {
		return $this->_parser;
	}
	/**
	 * This method allows to set the list of parameter. Such list must be an
	 * array like this:
	 * @code
	 * array(
	 *	"key1=value1",
	 * 	"key2",
	 * 	"key3=value3"
	 * )
	 * @endcode
	 *
	 * @param string[] $params List of parameters to be set. When null, this
	 * method works as a getter.
	 * @return string[string] Returns the current list of paramenters.
	 */
	public function & params($params = null) {
		//
		// Cheking if ther this is a list to be set.
		if($params !== null) {
			$list = array();
			//
			// Analyzing each parameter.
			foreach($params as $param) {
				// Expanding the parameter to separate the name
				// from it's value.
				$values = explode("=", $param);
				// If there is no value, it's assumed to be a
				// boolean parameter and it's value to be true.
				if(!isset($values[1])) {
					$values[1] = true;
				}
				$list[$values[0]] = $values[1];
			}
			//
			// Updating the list of parameters.
			$this->_params = $list;
		}

		return $this->_params;
	}
	/**
	 * This method allows to set the parent node for the current one.
	 *
	 * @param WCParserNode $parentNode Pointer to the parent node. When it
	 * is null, this method works as a getter.
	 * @return WCParserNode Return the current parent node.
	 */
	public function parentNode(WCParserNode &$parentNode = null) {
		//
		// When $parentNode is not null, it means it should be set as
		// parent.
		if($parentNode !== null) {
			$this->_parentNode = $parentNode;
		}

		return $this->_parentNode;
	}
}
?>